package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"sync"
	"time"

	"github.com/xjtulls/server/proto/heartbeat"
	"google.golang.org/grpc"
)

type server struct {
	heartbeat.UnimplementedHeartbeatServiceServer
}

// 用于存储客户端心跳信息，使用 sync.Map 以保证线程安全
var onlineClients sync.Map

// 每个客户端的心跳超时时间
const heartbeatTimeout = 30 * time.Second

// 清理超时客户端的后台任务，每 60 秒执行一次
func cleanupClients() {
	ticker := time.NewTicker(60 * time.Second)
	defer ticker.Stop()

	for {
		<-ticker.C
		onlineClients.Range(func(key, value interface{}) bool {
			if time.Since(value.(time.Time)) > heartbeatTimeout {
				// 超过超时时间，认为客户端离线，删除它
				onlineClients.Delete(key)
				fmt.Printf("Client %s has been removed due to timeout\n", key)
			}
			return true
		})
	}
}

// 处理客户端心跳的接口方法
func (s *server) SendHeartbeat(ctx context.Context, req *heartbeat.HeartbeatRequest) (*heartbeat.HeartbeatResponse, error) {
	clientID := req.GetClientId()
	// 更新客户端的心跳时间
	onlineClients.Store(clientID, time.Now())
	// 客户端根绝error判断 心跳是否成功，不返回当前在线数量
	return nil, nil
}

// 查询在线客户端数量的 HTTP 处理函数
func onlineClientsHandler(w http.ResponseWriter, r *http.Request) {
	// 获取在线客户端数量
	count := 0
	onlineClients.Range(func(_, _ interface{}) bool {
		count++
		return true
	})

	// 返回在线客户端数量的 JSON 响应
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]int{"online_clients": count})
}

func main() {
	// 设置监听地址
	listen, err := net.Listen("tcp", ":8001")
	if err != nil {
		fmt.Printf("failed to listen: %v", err)
		return
	}

	// 创建 gRPC 服务器
	s := grpc.NewServer()

	// 注册 gRPC 服务
	heartbeat.RegisterHeartbeatServiceServer(s, &server{})

	// 启动清理超时客户端的后台任务
	go cleanupClients()

	// 启动 HTTP 服务器，查询在线客户端数量
	http.HandleFunc("/online-clients", onlineClientsHandler)
	go func() {
		http.ListenAndServe(":8080", nil)
	}()

	// 启动 gRPC 服务器
	defer func() {
		s.Stop()
		listen.Close()
	}()
	fmt.Println("Serving gRPC on port 8001...")
	fmt.Println("Serving HTTP on port 8080...")

	// 开始 gRPC 服务
	err = s.Serve(listen)
	if err != nil {
		fmt.Printf("failed to serve: %v", err)
		return
	}
}
